package com.heima.wemedia.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.common.dtos.PageResult;
import com.heima.common.dtos.ResponseResult;
import com.heima.common.enums.AppHttpCodeEnum;
import com.heima.common.exception.LeadException;
import com.heima.common.threadlocal.UserThreadLocalUtils;
import com.heima.file.service.MinioService;
import com.heima.model.media.dtos.WmMaterialDto;
import com.heima.wemedia.mapper.WmMaterialMapper;
import com.heima.wemedia.pojo.WmMaterial;
import com.heima.wemedia.pojo.WmNewsMaterial;
import com.heima.wemedia.service.WmMaterialService;
import com.heima.wemedia.service.WmNewsMaterialService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.List;
import java.util.UUID;

/**
 * <p>
 * 自媒体图文素材信息表 服务实现类
 * </p>
 *
 * @author HM
 * @since 2023-03-22
 */
@Slf4j
@Service
public class WmMaterialServiceImpl extends ServiceImpl<WmMaterialMapper, WmMaterial> implements WmMaterialService {


    @Autowired
    MinioService minioService;

    @Autowired
    WmNewsMaterialService newsMaterialService;

    /**
     * 分页当前用户的查询文章素材列表
     *
     * @param dto
     * @return
     */
    @Override
    public PageResult<WmMaterial> findByPage(WmMaterialDto dto) {
        // 构建查询条件
        LambdaQueryWrapper<WmMaterial> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(WmMaterial::getUserId, UserThreadLocalUtils.getUserId());
        queryWrapper.eq(dto.getIsCollection() != null && dto.getIsCollection() != 0
                , WmMaterial::getIsCollection
                , dto.getIsCollection());
        // 构建分页条件
        Page<WmMaterial> ipage = new Page<>(dto.getPage(), dto.getSize());
        this.page(ipage, queryWrapper);
        // 构建响应数据并返回
        return new PageResult<>(dto.getPage(), dto.getSize(), ipage.getTotal(), ipage.getRecords());
    }


    /**
     * 上传图片到oss云存储
     *
     * @param file
     * @return
     */
    @Override
    public ResponseResult<String> uploadPicture(MultipartFile file) {

        Integer userId = this.checkLogin();
        if (file == null || StringUtils.isBlank(file.getOriginalFilename())) {
            log.error("图片上传参数错误! MultipartFile = {}", file);
            throw new LeadException(AppHttpCodeEnum.PARAM_INVALID);
        }

        String originalFilename = file.getOriginalFilename();
        // 新的文件名为 uuid(去掉 - ) + 原始文件后缀
        String newFileName = UUID.randomUUID().toString().replace("-", "")
                + originalFilename.substring(originalFilename.lastIndexOf("."));
        log.info("文件名为: {}", newFileName);
        try {
            String url = minioService.uploadImgFile("", newFileName, file.getInputStream());
            this.save(this.buildWmMaterial(url));
            return ResponseResult.ok(url);
        } catch (IOException e) {
            e.printStackTrace();
            log.error("图片上传Minio异常! 异常信息为:{}", ExceptionUtils.getStackTrace(e));
            throw new LeadException(AppHttpCodeEnum.UPDATE_ERROR);
        }


    }

    /**
     * 从ThreadLocal中获取UserId并检查userId是否合法
     *
     * @return userId
     */
    private Integer checkLogin() {
        Integer userId = UserThreadLocalUtils.getUserId();
        if (userId == null || userId == 0) {
            throw new LeadException(AppHttpCodeEnum.NEED_LOGIN);
        }
        return userId;
    }

    /**
     * 根据素材id 修改素材收藏状态
     *
     * @param id           素材id
     * @param isCollection 收藏状态
     * @return
     */
    @Override
    public void setIsCollectionById(Integer id, boolean isCollection) {
        // 检查用户是否登录
        Integer userId = this.checkLogin();
        // 检查用户权限
        checkUserAuth(id, userId);

        WmMaterial material = new WmMaterial();
        material.setId(id);
        material.setIsCollection(isCollection);
        this.updateById(material);
    }

    /**
     * 检查素材是否存在; 检查该用户是否有修改该素材的权限
     *
     * @param id
     * @param userId
     */
    private void checkUserAuth(Integer id, Integer userId) {
        WmMaterial wmMaterialDb = this.getById(id);
        if (wmMaterialDb == null) {
            log.error("无法根据素材id从数据库中查询到对应素材记录! {}", id);
            throw new LeadException(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        if (!wmMaterialDb.getUserId().equals(userId)) {
            log.error("当前用户id下并没有该自媒体素材! userId = {}", userId);
            throw new LeadException(AppHttpCodeEnum.NO_OPERATOR_AUTH);
        }
    }

    /**
     * 删除自媒体用户素材, 被文章引用的素材不能被删除
     *
     * @param id
     */
    @Override
    public void deleteMaterial(Integer id) {
        Integer userId = this.checkLogin();
        this.checkUserAuth(id, userId);
        boolean isInNews = this.checkInNews(id);
        if (isInNews) {
            throw new LeadException(AppHttpCodeEnum.DATA_CAN_NOT_DEL);
        }
        this.removeById(id);

    }

    /**
     * 根据图片的url集合查询WmMaterial集合
     *
     * @param url 图片url集合
     * @return List<WmMaterial>
     */
    @Override
    public List<WmMaterial> findByImages(List<String> url) {
        if (CollectionUtils.isEmpty(url)) {
            return null;
        }

        LambdaQueryWrapper<WmMaterial> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(WmMaterial::getUrl, url);


        return this.list(queryWrapper);
    }

    /**
     * 删除素材时 检查该素材是否被文章所引用.
     *
     * @param id
     * @return 如果引用返回true; 没有引用返回false;
     */
    private boolean checkInNews(Integer id) {
        LambdaQueryWrapper<WmNewsMaterial> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(WmNewsMaterial::getMaterialId, id);
        queryWrapper.last("limit 1");
        List<WmNewsMaterial> newsMaterials = newsMaterialService.list(queryWrapper);
        return !CollectionUtils.isEmpty(newsMaterials);
    }


    /**
     * 根据素材url构material对象以用于保存到db
     *
     * @param url
     * @return
     */
    private WmMaterial buildWmMaterial(String url) {
        WmMaterial wmMaterial = new WmMaterial();
        wmMaterial.setUrl(url);
        wmMaterial.setIsCollection(false);
        wmMaterial.setUserId(UserThreadLocalUtils.getUserId());
        // 素材类型 0为图片 1为视频
        wmMaterial.setType(0);
        return wmMaterial;
    }
}
